home *** CD-ROM | disk | FTP | other *** search
- #include <dos.h>
- #include <string.h>
- #include <conio.h>
- #include <mem.h>
- #include "hdinfo.h"
-
- unsigned secbuf[2][256];
- unsigned char biosbuf[64];
-
- int drive0;
- int drive1;
- long thcap;
- unsigned char temp;
-
- void readsect( int drive)
- // This function reads the drive parameter directly into
- // 256 byte buffer. A 256 byte sector must be read, despite
- // the fact that only the first few bytes are actually useful
- // (see ideinfo struct)
- {
- int i;
-
- outp(HDC_SDH, 0xA0 + (drive<<4)); // Setup task file parameter
- outp(HDC_COMMAND, HDC_COMMAND_READPAR); // Issue read parameters command
- while(inp(HDC_STATUS) & HDC_STATUS_BUSY); // Poll DRQ
- for (i=0; i<256; ++i) // Read Sector
- secbuf[drive][i] = inpw(HDC_DATA);
- };
-
- void interpret_info( int drive)
- // now interpret the data read by the previous function
- {
- int i, k;
- char c;
- char s[80];
- struct ideinfo *id = (struct ideinfo *)secbuf[drive];
-
- thcap = ((long)id->fixcyls * id->heads);
- id->capacity = ((double)thcap * id->sectors) / 2048;
- id->bioscapacity = ((double)id->biosheads * id->biossecs * id->bioscyls)/2048;
-
- // ascii strings read from the drive are read as INTS with the
- // opposite high/low byte ordering than the PC.
- // Therefore we must swap alternate bytes to return
- // to normal intel 80x86 ordering.
-
- // fix serial string
- for(i=0; i < 10; ++i)
- {
- c = id->serial[i*2];
- id->serial[i*2] = id->serial[i*2+1];
- id->serial[i*2+1] = c;
- };
-
- // fix firmware revision string
- for(i=0; i < 4; ++i)
- {
- c = id->firmware[i*2];
- id->firmware[i*2] = id->firmware[i*2+1];
- id->firmware[i*2+1] = c;
- };
-
- // fix model information string
- for(i=0; i < 20; ++i)
- {
- c = id->model[i*2];
- id->model[i*2] = id->model[(i*2)+1];
- id->model[i*2+1] = c;
- };
-
- // for Seagate and Western Digital drives, expand the model
- // data so it is clear who the manufacturer is. There are
- // probably umpteen more drives where this is necessary, but
- // these are the ones I come across on a day to day basis.
- if( memicmp( id->model, "WDC", 3) == 0)
- {
- strcpy( s, "Western Digital -");
- strcat( s, (char *)id->model+3);
- strncpy( id->model, s, 40);
- };
- if( memicmp( id->model, "st", 2) == 0)
- {
- strcpy( s, "Seagate - ST");
- strcat( s, (char *)id->model+2);
- strncpy( id->model, s, 40);
- };
-
- // if controller type is 4 or above it is unknown
- if( id->contype > 4) id->contype = 4;
-
- // convert the dblword flag into an integer value indicating
- // the number of bits (16 or 32) that can be transfered in a single
- // read/write via the hard drive controller
- ++id->dblword <<= 4;
-
- id->bestcyls = id->fixcyls;
- id->bestheads = id->heads;
- id->bestsecs = id->sectors;
-
- // if the number of physical cylinders is greater than 1024
- // then the drive internally remaps its configuration to suit
- // the PC bios (which only allows a maximum of 1024 cylinders).
- // We therefore need to calculate BIOS settings which are legal
- // (as far as the BIOS is concerned) but which still give us 100%
- // use of the physical drive space. All drives that I have
- // tested seem to hold the sector/cylinders constant and modify
- // the number of heads on the drive.
- // BIOS uses allows the following maximum values:-
- // Cylinders = 1024 : 10 bits
- // Heads = 256 : 8 bits
- // Sectors/Cylinder = 64 : 5 bits
- if (id->fixcyls >= 1024)
- {
- for ( i = id->heads; i < 256 ; i++)
- if ( ((thcap % i) == 0) && ((thcap / i) < 1024) )
- {
- id->bestcyls = thcap / i;
- id->bestheads = i;
- id->bestsecs = id->sectors;
- break;
- };
- // if no factors can be found and we still have over 1024 cylinders
- // then truncate the excess - some Maxtor drive do this (which means
- // that you can never use all the space on those models - on a PC)
- if (id->bestcyls >= 1024) id->bestcyls = 1024;
- };
- };
-
-
- int check_drive( int drive)
- // Check to see if the drive exists or not.
- // Returns true if the drive is there.
- {
- outp(HDC_SDH, 0xA0 + (drive<<4)); // Setup task file parameter
- if (inp(HDC_STATUS) == 0xFF) return(0); // if status = 0xff then no disk
- while(inp(HDC_STATUS) & HDC_STATUS_BUSY); // Poll DRQ and wait if necc.
- outp(HDC_CYLLOW, 0xAA); // test even bits in port
- if (inp(HDC_CYLLOW) != 0xAA) return(0); // if change then no disk
- outp(HDC_CYLLOW, 0x55); // test odd bits in port
- if (inp(HDC_CYLLOW) != 0x55) return(0); // if change then no disk
- if ((inp(HDC_STATUS) & 0x40) == 0) return(0); // check status changes
- return( 1);
- };
-
- void readbios( int drive)
- // get the drive information as it is stored for BIOS use
- {
- union REGS regs;
- struct ideinfo *id = (struct ideinfo *)secbuf[drive];
-
- // use BIOS interrupt 0x13 function 8 to get drive details
- regs.h.ah = 0x08;
- regs.h.dl = drive+0x80; // bit 7 set for hard drives
- int86(0x13, ®s, ®s);
- if (regs.h.dl < (drive+1)) return;
- id->biosheads = regs.h.dh + 1;
- id->biossecs = regs.h.cl & 0x3f;
-
- // for some reason the BIOS int 0x13 funct. 8 does not return
- // the same number as cylinders as the CMOS settings for the
- // drive (it is always 1 or 2 short). However reading the
- // number of cylinder directly from the drive parameter table
- // gives the correct result (where does BIOS go wrong?).
-
- if (drive == 0) id->bioscyls = **(unsigned int far * far *)(0x41 * 4);
- if (drive == 1) id->bioscyls = **(unsigned int far * far *)(0x46 * 4);
- };
-
-
- void readdrives( void)
- // This is the main function which calls all the rest.
- {
- outp(HDC_FIXED, 0); // Disable drive interrupts
- drive0 = check_drive( DRIVE_0); // check that drive 0 exists
- drive1 = check_drive( DRIVE_1); // check that drive 1 exists
- if (drive0) readsect( DRIVE_0); // if exists read data for drive 0
- if (drive1) readsect( DRIVE_1); // if exists read data for drive 1
- outp(HDC_FIXED, HDC_FIXED_IRQ); // Re-enable disk interrupts
- if (drive0) readbios( DRIVE_0); // Get Bios data for drive 0
- if (drive1) readbios( DRIVE_1); // Get Bios data for drive 1
-
- if (drive0) interpret_info( DRIVE_0); // Calculate capacity etc
- if (drive1) interpret_info( DRIVE_1); // calculate stats for drive 1
- };
-